home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d2
/
v8n12.arc
/
XMSDISK.ASM
< prev
Wrap
Assembly Source File
|
1989-04-05
|
28KB
|
644 lines
title XMSDISK XMS-aware RAMdisk
page 55,132
; XMSDISK.ASM --- XMS-aware RAMdisk device driver
; Copyright (C) 1989 Ziff Davis Communications
; PC Magazine * Ray Duncan
; Also requires ITOA.ASM and ATOI.ASM.
;
; To build: MASM XMSDISK;
; MASM ATOI;
; MASM ITOA;
; LINK XMSDISK+ATOI+ITOA;
; EXE2BIN XMSDISK.EXE XMSDISK.BIN
; DEL XMSDISK.EXE
;
; To install: copy XMSDISK.SYS to the boot disk, add
;
; DEVICE=XMSDISK.BIN nnnK
;
; to the CONFIG.SYS file. This must follow
; the DEVICE= line that loads the XMM (usually
; HIMEM.SYS). The parameter nnn is the desired
; RAMdisk size in KB. If nnn is missing or zero,
; all available extended memory is used.
;
_TEXT segment public 'CODE'
extrn atoi:near
extrn itoa:near
assume cs:_TEXT,ds:_TEXT,es:NOTHING
org 0
maxcmd equ 24 ; maximum driver command code
cr equ 0dh ; ASCII carriage return
lf equ 0ah ; ASCII line feed
blank equ 020h ; ASCII space code
eom equ '$' ; end of message indicator
secsize equ 512 ; bytes per sector (IBM standard)
dirsize equ 256 ; entries in root directory
request struc ; request packet template
len db ? ; length of request packet
unit db ? ; unit number for this request
command db ? ; request packet's command code
status dw ? ; status returned by driver
db 8 dup (?) ; reserved area
media db ? ; media descriptor byte
address dd ? ; memory address for transfer
count dw ? ; byte/sector count value
sector dw ? ; starting sector value
request ends ; end of request packet template
header equ $ ; device driver header
dd -1 ; link to next driver
dw 0 ; device attribute word
dw strat ; device "Strategy" entry point
dw intr ; device "Interrupt" entry point
db 1 ; number of units, this device
db 7 dup (0) ; reserved (block drivers)
rqptr dd ? ; far pointer to request packet
savesp dw 0 ; save kernel SS:SP during switch
savess dw 0 ; to driver's private stack
xmm dd 0 ; address of XMM entry point
handle dw 0 ; handle for extended memory block
total dw 0 ; total extended mem available (KB)
largest dw 0 ; largest free block available (KB)
alloc dw 0 ; extended memory allocated (KB)
clust dw 0 ; total clusters in RAMdisk
xfersec dw 0 ; current sector for transfer
xfercnt dw 0 ; sectors successfully transferred
xferreq dw 0 ; number of sectors requested
array dw bpb ; array of pointers to BPBs
; for each logical unit
movpars equ $ ; XMS Function 0BH parameter block
movelen dd 0 ; length to move in bytes
shandle dw 0 ; source handle
soffset dd 0 ; source offset or far pointer
dhandle dw 0 ; destination handle
doffset dd 0 ; destination offset or far pointer
bootrec equ $ ; boot record for logical sec. 0
jmp $ ; phony JMP at start of boot
nop ; sector (must be 3 bytes)
db 'IBM 3.3' ; OEM identity field
; BIOS Parameter Block (BPB)
bpb dw secsize ; 0 bytes per sector
db 2 ; 2 sectors per cluster
dw 1 ; 3 reserved sectors
db 1 ; 5 number of FATs
dw dirsize ; 6 root directory entries
dw 0 ; 8 total sectors
db 0f8h ; 0AH medium descriptor byte
dw 0 ; 0BH sectors per FAT
bootrec_len equ $-bootrec ; length of boot record
even ; force word alignment
dw 128 dup (0)
stk equ $ ; local stack for driver
;
; Driver 'strategy' routine; called by MS-DOS kernel with
; ES:BX pointing to driver request packet.
;
strat proc far ; driver 'strategy' routine
mov word ptr cs:rqptr,bx ; save request packet address
mov word ptr cs:rqptr+2,es
ret ; back to MS-DOS kernel
strat endp
;
; Driver 'interrupt' routine, called by MS-DOS kernel immediately
; after call to 'strategy' routine to process I/O request.
;
intr proc far
push ax ; save all registers
push bx
push cx
push dx
push ds
push es
push di
push si
push bp
mov ax,cs ; make local data addressable
mov ds,ax
mov savess,ss ; save DOS kernel's stack
mov savesp,sp
mov ss,ax ; set SS:SP to point to
mov sp,offset stk ; (larger) local stack
les di,rqptr ; ES:DI = request packet
mov bl,es:[di.command] ; get BX = command code
xor bh,bh
cmp bx,maxcmd ; make sure it's legal
jle intr1 ; jump, function code is ok
mov ax,8003h ; return 'unknown command' error
jmp intr2
intr1: shl bx,1 ; branch to command code routine
call word ptr [bx+dispch] ; must return AX = status
les di,rqptr ; ES:DI = request packet again
intr2: or ax,0100h ; merge 'done' bit into status
mov es:[di.status],ax ; store into request packet
mov ss,savess ; restore DOS kernel's stack
mov sp,savesp
pop bp ; restore general registers
pop si
pop di
pop es
pop ds
pop dx
pop cx
pop bx
pop ax
ret ; back to kernel
intr endp
;
; Dispatch table for driver commands
;
dispch dw init ; 0 = initialize driver
dw medchk ; 1 = media check on block device
dw bldbpb ; 2 = build BIOS parameter block
dw error ; 3 = I/O control read
dw read ; 4 = read from device
dw error ; 5 = non-destructive read
dw error ; 6 = return current input status
dw error ; 7 = flush device input buffers
dw write ; 8 = write to device
dw write ; 9 = write with verify
dw error ; 10 = return current output status
dw error ; 11 = flush output buffers
dw error ; 12 = I/O control write
dw error ; 13 = device open (DOS 3.0+)
dw error ; 14 = device close (DOS 3.0+)
dw error ; 15 = removeable media (DOS 3.0+)
dw error ; 16 = output until busy (DOS 3.0+)
dw error ; 17 = not used
dw error ; 18 = not used
dw error ; 19 = generic IOCTL (DOS 3.2+)
dw error ; 20 = not used
dw error ; 21 = not used
dw error ; 22 = not used
dw error ; 23 = get logical device (DOS 3.2+)
dw error ; 24 = set logical device (DOS 3.2+)
;
; Media Check routine (command code 1). Returns code indicating
; whether medium has been changed since last access.
;
medchk proc near
mov byte ptr es:[di+14],1 ; return "not changed" code
xor ax,ax ; return success status
ret
medchk endp
;
; Build BPB routine (command code 2). Returns pointer to valid
; BIOS Parameter Block for logical drive.
;
bldbpb proc near
mov word ptr es:[di+20],cs ; put BPB address in packet
mov word ptr es:[di+18],offset bpb
xor ax,ax ; return success status
ret
bldbpb endp
;
; Read routine (command code 4). Transfers logical sector(s)
; from RAMdisk storage to specified address.
;
read proc near
mov ax,es:[di.sector] ; ES:DI = request packet
mov xfersec,ax ; save starting sector number
mov ax,es:[di.count]
mov xferreq,ax ; save sectors requested
mov xfercnt,0 ; init sectors transferred count
mov ax,word ptr es:[di.address]
mov word ptr doffset,ax ; requestor's buffer address
mov ax,word ptr es:[di.address+2]
mov word ptr doffset+2,ax
mov ax,handle ; source handle = extended
mov shandle,ax ; memory handle
mov dhandle,0 ; destination handle = 0
mov word ptr movelen,secsize; logical sector length
read1: mov ax,xfercnt ; done with all sectors yet?
cmp ax,xferreq
je read2 ; jump if transfer completed
mov ax,xfersec ; source offset =
mul bpb ; sector no. * bytes/sector
mov word ptr soffset,ax
mov word ptr soffset+2,dx
mov ah,0bh ; move this sector from
mov si,offset movpars ; extended memory to requestor
call xmm
or ax,ax ; any error?
jz read4 ; yes, abort transfer
inc xfersec ; advance sector and address
add word ptr doffset+2,(secsize/16)
inc xfercnt ; count sectors transferred
jmp read1
read2: ; all sectors transferred,
xor ax,ax ; return success status
read3: les di,rqptr ; get address of request packet
mov bx,xfercnt ; return sectors transferred count
mov es:[di.count],bx
ret
read4: mov ax,800bh ; XMM error, return 'read fault'
jmp read3
read endp
;
; Write (command code 8) and Write with Verify (command code 9)
; routine. Transfers logical sector(s) from specified address
; to RAMdisk storage.
;
write proc near
mov ax,es:[di.sector] ; ES:DI = request packet
mov xfersec,ax ; save starting sector number
mov ax,es:[di.count]
mov xferreq,ax ; save sectors requested
mov xfercnt,0 ; init sectors transferred count
mov ax,word ptr es:[di.address]
mov word ptr soffset,ax ; requestor's buffer address
mov ax,word ptr es:[di.address+2]
mov word ptr soffset+2,ax
mov ax,handle ; destination handle = extended
mov dhandle,ax ; memory handle
mov shandle,0 ; zero out source handle
mov word ptr movelen,secsize; logical sector length
write1: mov ax,xfercnt ; done with all sectors yet?
cmp ax,xferreq
je write2 ; jump if transfer completed
mov ax,xfersec ; destination offset =
mul bpb ; sector no. * bytes/sector
mov word ptr doffset,ax
mov word ptr doffset+2,dx
mov ah,0bh ; move this sector from
mov si,offset movpars ; requestor to extended memory
call xmm
or ax,ax ; any error?
jz write4 ; yes, abort transfer
inc xfersec ; advance sector and address
add word ptr soffset+2,(secsize/16)
inc xfercnt ; count sectors transferred
jmp write1
write2: ; all sectors successfully
xor ax,ax ; transferred, return ok status
write3:
les di,rqptr ; get address of request packet
mov bx,xfercnt ; return actual transfer count
mov es:[di.count],bx
ret
write4: mov ax,800ah ; XMM error, return 'write fault'
jmp write3
write endp
;
; Dummy routine for unsupported driver command codes
;
error proc near
mov ax,8103h ; return 'unknown command' error
ret
error endp
;
; Initialization routine, called at driver load time. Returns
; address of 'init' label to MS-DOS as start of free memory, so
; that memory occupied by 'init' and its subroutines is reclaimed.
;
init proc near ; command code 0 = initialize
mov ax,4300h ; check if XMM present
int 2fh
cmp al,80h ; status = installed?
je init1 ; yes, proceed
mov dx,offset msg1 ; no, display error message
jmp init8 ; and abort installation
init1: mov ax,4310h ; XMM available, request entry
int 2fh ; point and save it
mov word ptr xmm,bx
mov word ptr xmm+2,es
mov ah,8 ; get available extended memory
call xmm ; transfer to XMM
mov total,dx ; save total KB available
mov largest,ax ; save largest free block
cmp largest,64 ; at least 64 KB available?
jae init2 ; yes, proceed
mov dx,offset msg2 ; no, display error message
jmp init8 ; and abort installation
init2: les di,rqptr ; let ES:DI = request packet
lds si,es:[di+18] ; point to CONFIG.SYS line
init3: lodsb ; scan for end of driver name
cmp al,blank
ja init3 ; loop while within name
dec si ; point to delimiter and
call atoi ; convert size parameter
push cs ; make our data addressable
pop ds
or ax,ax ; size parameter missing?
jz init4 ; yes, use all extended memory
cmp ax,largest ; requested > available?
jna init5 ; no, jump
init4: mov ax,largest ; use all of available memory
init5: mov alloc,ax ; save requested size
mov dx,ax ; DX = RAMdisk size in KB
mov ah,9 ; XMS function 9 = allocate
call xmm ; transfer to XMM
or ax,ax ; allocation successful?
jnz init6 ; yes, proceed
mov dx,offset msg3 ; no, display error message
jmp init8 ; and abort installation
init6: mov handle,dx ; save extended memory handle
call makebpb ; set up Bios Parameter Block
call format ; format the RAMdisk
jnc init7 ; jump if no error during format
mov dx,offset msg4 ; formatting error, exit
jmp init8
init7: les di,rqptr ; let ES:DI = request packet
mov al,es:[di+22] ; get drive code from header,
add al,'A' ; convert to ASCII for output
mov ident1,al
mov ax,total ; convert KB available to ASCII
mov si,offset ident2
mov cx,10
call itoa
mov ax,largest ; convert KB largest free block
mov si,offset ident3
call itoa
mov ax,alloc ; convert KB allocated to ASCII
mov si,offset ident4
call itoa
mov dx,offset ident ; display sign-on message
mov ah,9 ; function 9 = display string
int 21h ; transfer to MS-DOS
; set top of driver address
mov word ptr es:[di.address],offset init
mov word ptr es:[di.address+2],cs
mov byte ptr es:[di+13],1 ; indicate 1 logical unit
mov word ptr es:[di+20],cs ; return address of BPB array
mov word ptr es:[di+18],offset array
jmp init9
init8: ; XMSDISK initialization failed
push dx ; save specific error message
mov dx,offset errmsg ; display error heading
mov ah,9 ; function 9 = display string
int 21h ; transfer to MS-DOS
pop dx ; display error description
mov ah,9 ; function 9 = display string
int 21h ; transfer to MS-DOS
les di,cs:rqptr ; let ES:DI=request packet
; set driver end = driver start
mov word ptr es:[di.address],0
mov word ptr es:[di.address+2],cs
mov byte ptr es:[di+13],0 ; set no. of logical units = 0
init9: xor ax,ax ; return success status
ret
init endp
;
; Set up total sectors and sectors per FAT fields of BIOS Parameter
; Block according to size of RAMdisk. Calculate and save total
; clusters (indicates whether 12-bit or 16-bit FAT will be used).
;
makebpb proc near
mov ax,alloc ; get size of allocated block
mov dx,1024 ; convert KB to bytes
mul dx ; divided by bytes/sector
div word ptr bpb ; gives AX = total sectors
mov bpb+8,ax ; update BPB with total sectors
xor dx,dx ; sectors / (sectors/cluster)
xor ch,ch ; = total clusters
mov cl,byte ptr bpb+2
div cx
mov clust,ax ; save total clusters
cmp ax,4086 ; clusters < 4087?
jna makeb1 ; yes, jump
shl ax,1 ; no, assume 16-bit FAT
jmp makeb2 ; clusters * 2 = bytes/FAT
makeb1: mov dx,ax ; if clusters < 4087, 12-bit FAT
add ax,ax ; clusters * 1.5 = bytes/FAT
add ax,dx
shr ax,1
jnc makeb2
inc ax ; round bytes up if necessary
makeb2: xor dx,dx ; (bytes/FAT) / (bytes/sec)
div word ptr bpb ; = sectors/FAT
or dx,dx ; any remainder?
jz makeb3 ; no,jump
inc ax ; round up to next sector
makeb3: mov bpb+0bh,ax ; update FAT size in BPB
ret
makebpb endp
;
; Format RAMdisk. First write zeros into all sectors of reserved
; area, FAT, and root directory. Then copy phony boot record to
; boot sector, initialize medium ID byte at beginning of FAT, and
; place phony volume label in first sector of root directory.
;
format proc near
push ds ; initialize sector buffer
pop es ; to zeros so we can clear
mov di,offset secbuf ; out reserved area, FAT,
mov cx,secsize ; and root directory
xor al,al
rep stosb
mov ax,bpb+6 ; no. of directory entries
mov cx,32 ; * (32 bytes/entry)
mul cx ; = bytes in root directory
div bpb ; / (bytes/sector)
or dx,dx ; = sectors in root directory
jz fmt1
inc ax ; round up any partial sector
fmt1: add ax,bpb+3 ; + reserved sectors
add ax,bpb+0bh ; + sectors in FAT
mov xferreq,ax ; = total sectors to clear
mov xfercnt,0 ; initialize sector counter
; set up move parameter block
mov word ptr movelen,secsize; length to move
mov shandle,0 ; source handle and address
mov word ptr soffset,offset secbuf
mov word ptr soffset+2,cs
mov ax,handle ; destination extended memory
mov dhandle,ax ; block handle
mov word ptr doffset,0 ; initial destination offset
mov word ptr doffset+2,0
fmt2: mov ah,0bh ; write this sector
mov si,offset movpars ; DS:SI = parameter block
call xmm ; transfer to XMM
or ax,ax ; test move status
jnz fmt3
jmp fmt5 ; abort if move failed
fmt3: add word ptr doffset,secsize; increment destination address
adc word ptr doffset+2,0
mov ax,xfercnt ; count sectors initialized
inc ax
mov xfercnt,ax
cmp ax,xferreq ; done yet?
jne fmt2 ; not done, write another
mov ax,bpb+3 ; calculate offset of first
mul bpb ; FAT sector in RAMdisk buffer
mov word ptr doffset,ax ; set destination address
mov word ptr doffset+2,dx
mov al,byte ptr bpb+0ah ; set up medium ID byte
mov secbuf,al ; in first FAT sector
mov word ptr secbuf+1,-1 ; assume 12-bit FAT
cmp clust,4086 ; more than 4086 clusters?
jna fmt4 ; no, jump
mov secbuf+3,0ffh ; yes, use 16-bit FAT
fmt4: mov ah,0bh ; write first FAT sector
mov si,offset movpars
call xmm
or ax,ax ; test move status
jz fmt5 ; abort if move failed
mov word ptr doffset,0 ; offset of logical sector 0
mov word ptr doffset+2,0
mov word ptr soffset,offset bootrec
mov word ptr movelen,bootrec_len
mov ah,0bh ; copy phony boot record
mov si,offset movpars ; to logical sector 0
call xmm
or ax,ax ; test move status
jz fmt5 ; abort if move failed
mov ax,bpb+0bh ; calculate offset of first
add ax,bpb+3 ; root directory sector
mul bpb ; in RAMdisk buffer
mov word ptr doffset,ax
mov word ptr doffset+2,dx
mov word ptr soffset,offset volname
mov word ptr movelen,volname_len
mov ah,0bh ; copy phony volume label
mov si,offset movpars ; to first directory sector
call xmm
or ax,ax ; test move status
jz fmt5 ; abort if move failed
clc ; successful format,
ret ; return CY = clear
fmt5: stc ; format failed,
ret ; return CY = set
format endp
;
; Miscellaneous data used during initialization, then discarded.
;
ident db cr,lf,lf ; sign-on message
db 'XMSDISK Extended Memory RAMdisk'
db cr,lf
db 'Copyright (C) 1989 Ziff Davis Communications'
db cr,lf
db 'PC Magazine * Ray Duncan'
db cr,lf,lf
db 'XMSDISK will be drive '
ident1 db 'X:',cr,lf
db 'Extended memory available:'
ident2 db ' KB',cr,lf
db 'Largest free memory block:'
ident3 db ' KB',cr,lf
db 'Extended memory allocated:'
ident4 db ' KB',cr,lf,eom
errmsg db cr,lf
db 'XMSDISK installation error:'
db cr,lf,eom
msg1 db 'Extended Memory Manager not found.'
db cr,lf,eom
msg2 db 'Insufficient extended memory available.'
db cr,lf,eom
msg3 db 'Extended memory allocation failed.'
db cr,lf,eom
msg4 db 'Unable to format RAMdisk.'
db cr,lf,eom
volname db 'XMSDISK ' ; phony volume label
db 08h ; volume label attribute byte
db 10 dup (0)
dw 0 ; time = 00:00:00
dw 1241h ; date = February 1, 1989
db 6 dup (0)
volname_len equ $-volname
secbuf db secsize dup (?) ; sector buffer for format
_TEXT ends
end